﻿using System.Text;
using DatabaseGroup.SSIS.SourceAdapters.Model;
using DatabaseGroup.SSIS.SourceAdapters.View;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using System.Globalization;
using System.Text.RegularExpressions;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;

namespace DatabaseGroup.SSIS.SourceAdapters.Presenter
{
    /// <summary>
    /// Provides a set of common utils for use across all presenters
    /// </summary>
    public class PresenterUtils
    {
        /// <summary>
        /// Initializes the file model based on the settings 
        /// held within the component
        /// </summary>
        /// <param name="fileModel">The file model to initialize</param>
        /// <param name="componentModel">The component model to pull the file connection string from</param>
        /// <param name="view">The view to query the latest settings from</param>
        public static void ConfigureFileModel(ISourceFileModel fileModel, IComponentModel componentModel, IEditorBaseView view)
        {
            GeneralTabSettings generalTabSettings = view.GetTabSettings<GeneralTabSettings>(EditorViewTab.General);
            ColumnTabSettings columnTabSettings = view.GetTabSettings<ColumnTabSettings>(EditorViewTab.Columns);

            fileModel.FileName = componentModel.GetFileConnectionByName(generalTabSettings.FileConnection);
            fileModel.Encoding = CreateEncodingFromSettings(generalTabSettings);

            fileModel.ColumnDelimiter = DelimiterStringConverter.ToValueDelim(columnTabSettings.ColumnDelimiter);
            fileModel.RowDelimiter = DelimiterStringConverter.ToValueDelim(columnTabSettings.RowDelimiter);
            fileModel.ColumnNamesInFirstRow = generalTabSettings.ColumnNamesInFirstDataRow;
            fileModel.DataRowsToSkip = generalTabSettings.DataRowsToSkip;
            fileModel.HeaderRowDelimiter = DelimiterStringConverter.ToValueDelim(generalTabSettings.HeaderRowDelimiter);
            fileModel.HeaderRowsToSkip = generalTabSettings.HeaderRowsToSkip;
            fileModel.TextQualifier = DelimiterStringConverter.ToValueDelim(generalTabSettings.TextQualifier);
        }

        /// <summary>
        /// Queries the current General tab settings and creates the
        /// appropriate Encoding object
        /// </summary>
        /// <param name="settings">The general tab settings</param>
        /// <returns>The relevant encoding</returns>
        public static Encoding CreateEncodingFromSettings(GeneralTabSettings settings)
        {
            bool isUnicode = settings.IsUnicode;
            int codepage = ConvertStringToCodepage(settings.CodePage);

            if (isUnicode)
                return Encoding.Unicode;

            return Encoding.GetEncoding(codepage, new EncoderReplacementFallback("?"), new DecoderReplacementFallback("?"));
        }

        /// <summary>
        /// Creates a new instance of a ColumnProperty with default values
        /// </summary>
        /// <param name="useUnicode">True if the initial column datatype should be DT_WSTR</param>
        /// <returns>The configured ColumnProperty</returns>
        public static ColumnProperty CreateDefaultColumnProperty(bool useUnicode)
        {
            // TODO: remove hardcoded constants
            DataType datatype = useUnicode ? DataType.DT_WSTR : DataType.DT_STR;
            int codepage = useUnicode ? 0 : 1252;

            ColumnProperty column = new ColumnProperty("", 0, 0, datatype, 255, codepage);
            column.IsForOutput = true;
            column.ErrorHandling = ConvertDispositionToString(DTSRowDisposition.RD_RedirectRow);
            column.TruncationHandling = ConvertDispositionToString(DTSRowDisposition.RD_IgnoreFailure);

            return column;
        }

        /// <summary>
        /// Converts a locale ID into a view friendly formatted string
        /// </summary>
        /// <param name="localeID">The locale ID to convert</param>
        /// <returns>A view friendly locale string</returns>
        public static string ConvertLocaleIDToString(int localeID)
        {
            CultureInfo culture = CultureInfo.GetCultureInfo(localeID);
            return string.Format("{0} <{1}>", culture.EnglishName, culture.LCID);
        }

        /// <summary>
        /// Converts a view friendly locale string into its locale ID
        /// </summary>
        /// <param name="locale">The locale string to convert</param>
        /// <returns>The corresponding locale ID</returns>
        public static int ConvertStringToLocaleID(string locale)
        {
            Regex findId = new Regex(@"<(?<ID>\d+)>$");
            return int.Parse(findId.Match(locale).Groups["ID"].Value);
        }

        /// <summary>
        /// Converts a codepage to a view friendly formatted string
        /// </summary>
        /// <param name="codepage">The codepage to convert</param>
        /// <returns>A view friendly codepage string</returns>
        public static string ConvertCodepageToString(int codepage)
        {
            Encoding encoding = Encoding.GetEncoding(codepage);
            return string.Format("{0} ({1})", encoding.CodePage, encoding.EncodingName);
        }

        /// <summary>
        /// Converts a view friendly codepage string to its numeric value
        /// </summary>
        /// <param name="codepage">The view friendly codepage string</param>
        /// <returns>The numeric value of the codepage</returns>
        public static int ConvertStringToCodepage(string codepage)
        {
            Regex findCodepage = new Regex(@"^(?<Codepage>\d+)");
            return int.Parse(findCodepage.Match(codepage).Groups["Codepage"].Value);
        }

        /// <summary>
        /// Converts a DTSRowDisposition value to a view friendly string
        /// </summary>
        /// <param name="disposition">The DTSRowDisposition to convert</param>
        /// <returns>The view friendly string of the disposition</returns>
        public static string ConvertDispositionToString(DTSRowDisposition disposition)
        {
            // TODO: MessageStrings
            switch (disposition)
            {
                case DTSRowDisposition.RD_FailComponent:
                    return "Fail component";
                case DTSRowDisposition.RD_IgnoreFailure:
                    return "Ignore and log failure";
                case DTSRowDisposition.RD_RedirectRow:
                    return "Redirect row";
                case DTSRowDisposition.RD_NotUsed:
                    return "Not used";
            }

            return null;
        }

        /// <summary>
        /// Converts a view friendly disposition string to the 
        /// corresponding DTSRowDisposition value
        /// </summary>
        /// <param name="disposition">The view friendly string of the disposition</param>
        /// <returns>The DTSRowDisposition value</returns>
        public static DTSRowDisposition ConvertStringToDisposition(string disposition)
        {
            // TODO: MessageStrings
            switch (disposition)
            {
                case "Fail component":
                    return DTSRowDisposition.RD_FailComponent;
                case "Ignore and log failure":
                    return DTSRowDisposition.RD_IgnoreFailure;
                case "Redirect row":
                    return DTSRowDisposition.RD_RedirectRow;
                default:
                    return DTSRowDisposition.RD_NotUsed;
            }
        }
    }
}
